package com.zoomabug.list;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

/**
 * 
 * {@link ArrayList} does not provide iterators that allow access the next
 * element of the list without advancing the cursor. This simple extension
 * provides both iterators that allow access to the next (or previous) element
 * without advancing the iterator.
 * 
 * @author Jeff Axelrod
 * 
 * @param <T>
 *           element type to be stored in the list
 */
public class PeekableArrayList<T> extends ArrayList<T> implements PeekableList<T> {
   private static final long serialVersionUID = 4888868747165406327L;

   @Override public PeekableListIterator<T> listIterator() {
      return new PeekableArrayListListIterator(super.listIterator());
   }

   @Override public PeekableIterator<T> iterator() {
      return new PeekableArrayListIterator(super.listIterator());
   }

   private class PeekableArrayListIterator implements PeekableIterator<T> {
      final private Iterator<T> iterator;
      private T next = null;

      public PeekableArrayListIterator(final Iterator<T> iterator) {
         this.iterator = iterator;
      }

      @Override public synchronized boolean hasNext() {
         return iterator.hasNext();
      }

      @Override public synchronized T next() {
         T t;
         if (next == null) {
            t = iterator.next();
         } else {
            t = next;
            next = null;
         }
         return t;
      }

      @Override public synchronized void remove() {
         iterator.remove();
      }

      @Override public synchronized T peekAtNext() {
         if (next == null)
            next = next();
         return next;
      }
   }

   private class PeekableArrayListListIterator implements PeekableListIterator<T> {
      final private ListIterator<T> listIterator;

      public PeekableArrayListListIterator(final ListIterator<T> listIterator) {
         this.listIterator = listIterator;
      }

      @Override public synchronized void add(T arg0) {
         listIterator.add(arg0);
      }

      @Override public synchronized boolean hasNext() {
         return listIterator.hasNext();
      }

      @Override public synchronized boolean hasPrevious() {
         return listIterator.hasPrevious();
      }

      @Override public synchronized T next() {
         return listIterator.next();
      }

      @Override public synchronized int nextIndex() {
         return listIterator.nextIndex();
      }

      @Override public synchronized T previous() {
         return listIterator.previous();
      }

      @Override public synchronized int previousIndex() {
         return listIterator.previousIndex();
      }

      @Override public synchronized void remove() {
         listIterator.remove();
      }

      @Override public synchronized void set(T arg0) {
         listIterator.set(arg0);
      }

      @Override public synchronized T peekAtNext() {
         T t = next();
         previous();
         return t;
      }

      @Override public synchronized T peekAtPrevious() {
         T t = previous();
         next();
         return t;
      }
   }
}